/**
 * @author : andy
 * @description : 路由相关的工具方法
 */
import type { AccessMenuItem } from "@/stores/access/types";
import type { RouteRecordRaw } from "vue-router";
type TreeConfigOptions = {
  /** 树遍历的子树的key值，默认为children，有可能是其他值 */
  childProps: string;
}
/**
 * 遍历树，并返回所有节点中指定的值的数组
 * @param tree 树数据
 * @param getValue 获取树节点值的函数
 * @param options 作为子节点数组的可选属性名称
 * @returns 所有节点中指定的值的数组
 */
export function traverseTreeValues<T , V> (tree: T[] , getValue: (node: T) => V , options: TreeConfigOptions = {childProps : 'children'}): V[] {
  const result: V[] = [];
  const childProps = options.childProps;
  const traverse = (treeNode: T) => {
    const value = getValue(treeNode);
    result.push(value);
    const children = treeNode[childProps as keyof T] as T[];
    if (!children) {
      return;
    }
    if (children.length > 0) {
      for (const child of children) {
        traverse(child);
      }
    }
  }
  for (const node of tree) {
    traverse(node);
  }
  return result.filter(item => !!item);
}
/**
 * 根据过滤条件，返回原数组数据结构的树数据
 * @param tree 树数据
 * @param filter 过滤函数
 * @param options 作为子节点数组的可选属性名称
 * @returns 过滤后的树数据（保存原来的结构）
 */
export function filterTree<T> (tree: T[] , filter: (node: T) => boolean , options: TreeConfigOptions = {childProps : 'children'}): T[] {
  const childProps = options.childProps;
  const _filterTree = (tree: T[]) => {
    return tree.filter((node: T) => {
      if (filter(node)) {
        if (node[childProps as keyof T]) {
          (node as Record<string , unknown>)[childProps] = _filterTree(node[childProps as keyof T] as T[]);
        }
        return true;
      }
      return false;
    })
  }
  return _filterTree(tree);
}
/**
 * 遍历树结构，给每一个树节点添加相应的属性
 * @param tree 树数据
 * @param add 需要给树结构添加的数据的方法
 * @param options 作为子节点数组的可选属性名称
 * @returns 返回添加数据后的树数据
 */
export function traverseTreeToAddProps<T , K extends T> (tree: T[] , add: (node: K) => void , options: TreeConfigOptions = {childProps : 'children'}): T[] {
  const childProps = options.childProps;
  const _traverse = (tree: T[]) => {
    return tree.map(node => {
      add(node as K);
      if (node[childProps as keyof T]) {
        (node as Record<string , unknown>)[childProps] = _traverse(node[childProps as keyof T] as T[]);
      }
      return node;
    })
  }
  return _traverse(tree);
}
/**
 * 通过给定的一个值，找到树结构对应的节点
 * @param tree 树数据
 * @param propName 树节点的属性key名称
 * @param value 给定的一个值，找到树节点中与这个值相等的节点
 * @param ooptions 指定树节点的哪个属性
 */
export function findTreeNodeByValue<T , K extends keyof T> (tree: T[] , propName: K , value: unknown , options: TreeConfigOptions = {childProps : 'children'}): T | null {
  let treeNode: T | null = null;
  const childProps = options.childProps;
  const _traverse = (tree: T[]) => {
    tree.map(node => {
      const propValue = node[propName];
      if (propValue && propValue === value) {
        treeNode = node;
      }
      const children = node[childProps as keyof T] as T[];
      if (children) {
        _traverse(children);
      }
    })
  }
  _traverse(tree);
  return treeNode;
}
/**
 * 根据返回的菜单列表，生成路由列表
 * @param routes 动态的路由列表（也就是我们应用中所有的可能是动态路由的列表）
 * @param menus 菜单列表
 */
export function generateAccessRoutes (routes: RouteRecordRaw[] , menus: AccessMenuItem[]) {
  // 获取菜单列表中的所有路径
  const paths = traverseTreeValues(menus , node => node.path , {childProps : 'children'});
  const accessRoutes = filterTree(routes , node => {
    let flag = false;
    for (let i = 0 ; i < paths.length ; i++) {
      if (paths[i] === node.redirect || paths[i] === node.path) {
        flag = true;
        break;
      }
    }
    return flag;
  } , {childProps : 'children'});
  // 遍历 menus，找到所有内嵌的菜单
  const iframeMenus = traverseTreeValues(menus , node => {
    if (node.isIframe) {
      return node
    }
  } , {childProps : 'children'});
  // 找到需要缓存的页面
  const keepAliveMenus = traverseTreeValues(menus , node => {
    if (node.isKeepAlive) {
      return node;
    }
  } , { childProps : 'children' });
  const keepAliveRoutes = traverseTreeValues(accessRoutes , node => {
    if (node.meta && node.meta.isKeepAlive) {
      return node;
    }
  } , { childProps : 'children' });
  traverseTreeToAddProps(accessRoutes , node => {
    const treeNode = findTreeNodeByValue(menus , 'path' , node.path , {childProps : 'children'});
    if (treeNode) {
      // 将菜单中的一些数据添加到路由对象的meta中
      node.meta = {
        ...node.meta,
        title : treeNode.name,
        fixed : treeNode.fixed || false,
        icon : treeNode.icon || ''
      }
    }
  } , { childProps : 'children' });
  return {
    accessRoutes,
    iframeMenus,
    keepAliveMenus,
    keepAliveRoutes
  };
}